/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi_flash.h
  * @brief   SPI Flash读写模块头文件
  *          支持W25Q系列、AT25系列等SPI Flash芯片
  ******************************************************************************
  */
/* USER CODE END Header */

#ifndef __SPI_FLASH_H__
#define __SPI_FLASH_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"

/* SPI Flash配置参数 ---------------------------------------------------------*/
#define FLASH_SPI_HANDLE        &hspi2          // 使用SPI2
#define FLASH_CS_PORT           GPIOB           // CS引脚端口改为GPIOB
#define FLASH_CS_PIN            GPIO_PIN_12     // CS引脚改为PB12
#define FLASH_TIMEOUT           1000            // 超时时间(ms)

/* SPI Flash命令定义 --------------------------------------------------------*/
#define FLASH_CMD_WRITE_ENABLE      0x06        // 写使能
#define FLASH_CMD_WRITE_DISABLE     0x04        // 写禁止
#define FLASH_CMD_READ_STATUS       0x05        // 读状态寄存器
#define FLASH_CMD_WRITE_STATUS      0x01        // 写状态寄存器
#define FLASH_CMD_READ_DATA         0x03        // 读数据
#define FLASH_CMD_FAST_READ         0x0B        // 快速读
#define FLASH_CMD_PAGE_PROGRAM      0x02        // 页编程
#define FLASH_CMD_SECTOR_ERASE      0x20        // 扇区擦除(4KB)
#define FLASH_CMD_BLOCK_ERASE_32K   0x52        // 块擦除(32KB)
#define FLASH_CMD_BLOCK_ERASE_64K   0xD8        // 块擦除(64KB)
#define FLASH_CMD_CHIP_ERASE        0xC7        // 芯片擦除
#define FLASH_CMD_POWER_DOWN        0xB9        // 掉电模式
#define FLASH_CMD_RELEASE_POWER_DOWN 0xAB       // 释放掉电模式
#define FLASH_CMD_DEVICE_ID         0x90        // 读设备ID
#define FLASH_CMD_JEDEC_ID          0x9F        // 读JEDEC ID

/* 状态寄存器位定义 ----------------------------------------------------------*/
#define FLASH_STATUS_BUSY           0x01        // 忙标志
#define FLASH_STATUS_WEL            0x02        // 写使能锁存

/* Flash参数定义 ------------------------------------------------------------*/
// 避免与HAL库的FLASH_PAGE_SIZE冲突
#ifndef SPI_FLASH_PAGE_SIZE
#define SPI_FLASH_PAGE_SIZE             256         // SPI Flash页大小(字节)
#endif

// 如果需要使用原来的宏名，可以这样定义：
#ifndef FLASH_PAGE_SIZE
#define FLASH_PAGE_SIZE             SPI_FLASH_PAGE_SIZE
#endif
#define FLASH_SECTOR_SIZE           4096        // 扇区大小(字节)
#define FLASH_BLOCK_SIZE_32K        32768       // 32KB块大小
#define FLASH_BLOCK_SIZE_64K        65536       // 64KB块大小

/* 函数声明 ------------------------------------------------------------------*/

/**
 * @brief  SPI Flash初始化
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_Init(void);

/**
 * @brief  读取Flash ID
 * @param  jedec_id: JEDEC ID缓冲区(3字节)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadID(uint8_t *jedec_id);

/**
 * @brief  读取设备ID
 * @param  device_id: 设备ID缓冲区(2字节)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadDeviceID(uint8_t *device_id);

/**
 * @brief  读取状态寄存器
 * @retval uint8_t 状态寄存器值
 */
uint8_t SPI_Flash_ReadStatus(void);

/**
 * @brief  等待Flash操作完成
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WaitForReady(void);

/**
 * @brief  写使能
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteEnable(void);

/**
 * @brief  写禁止
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteDisable(void);

/**
 * @brief  读取数据
 * @param  addr: 读取地址
 * @param  data: 数据缓冲区
 * @param  size: 读取字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadData(uint32_t addr, uint8_t *data, uint32_t size);

/**
 * @brief  快速读取数据
 * @param  addr: 读取地址
 * @param  data: 数据缓冲区
 * @param  size: 读取字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_FastRead(uint32_t addr, uint8_t *data, uint32_t size);

/**
 * @brief  页编程
 * @param  addr: 写入地址
 * @param  data: 数据缓冲区
 * @param  size: 写入字节数(不超过页大小)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_PageProgram(uint32_t addr, uint8_t *data, uint32_t size);

/**
 * @brief  写入数据(自动处理跨页)
 * @param  addr: 写入地址
 * @param  data: 数据缓冲区
 * @param  size: 写入字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteData(uint32_t addr, uint8_t *data, uint32_t size);

/**
 * @brief  扇区擦除(4KB)
 * @param  addr: 扇区地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_SectorErase(uint32_t addr);

/**
 * @brief  块擦除(32KB)
 * @param  addr: 块地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_BlockErase32K(uint32_t addr);

/**
 * @brief  块擦除(64KB)
 * @param  addr: 块地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_BlockErase64K(uint32_t addr);

/**
 * @brief  芯片擦除
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ChipErase(void);

/**
 * @brief  进入掉电模式
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_PowerDown(void);

/**
 * @brief  退出掉电模式
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReleasePowerDown(void);

/* 内联函数 ------------------------------------------------------------------*/

/**
 * @brief  CS引脚拉低(选中Flash)
 */
static inline void SPI_Flash_CS_Low(void)
{
    HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_RESET);
}

/**
 * @brief  CS引脚拉高(取消选中Flash)
 */
static inline void SPI_Flash_CS_High(void)
{
    HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_SET);
}

#ifdef __cplusplus
}
#endif

#endif /* __SPI_FLASH_H__ */